/* esta libreria tiene la funciÃ³n sleep*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include "libPlanificadorDeDisco.h"
#include <semaphore.h>
#include <sys/mman.h>
#include "signal.h"
#include "unix.h"

#define MAX_BUFFER 4163

void leerSector(uint32_t disco, uint16_t sector, char *retorno) {
	extern char* sectorOcupado;
	extern uint16_t tiempoLectura;
	extern char* ptrDisco;
	sleep(tiempoLectura);
	if (sectorOcupado[sector]) {
		if (msync(ptrDisco + sector * 512, 512, MS_SYNC) == -1) {
			printf("error en el msync()\n");
			signal(SIGUSR1, senalFin);
			return;
		}
	}
	memcpy(retorno, ptrDisco + sector * 512, 512);
	return;
}

void escribirSector(uint32_t disco, uint16_t sector, char *contenido) {
	extern char* sectorOcupado;
	extern uint16_t tiempoEscritura;
	extern char* ptrDisco;
	sleep(tiempoEscritura);
	memcpy(ptrDisco + sector * 512, contenido, 512);
	sectorOcupado[sector] = 1;

	return;
}

uint16_t buscarTiempo(chs_t posicion) {
	printf("inicio tiempo \n");
	extern uint16_t RPM;
	extern chs_t cabezal;
	extern chs_t CHS;
	extern uint16_t tiempoSaltoPistas;
	float tiempoPorSector;
	uint16_t sectoresAtravezados;
	uint16_t tiempoPista, tiempoSector;
	tiempoPorSector = (1 / (((float) RPM) / 60000)) / CHS.sector;
	printf("tiempo por sector: %2f ms\n", tiempoPorSector);
	if (posicion.pista != cabezal.pista) {
		tiempoPista = (abs(posicion.pista - cabezal.pista) * tiempoSaltoPistas);
	}
	printf("tiempo pista: %d ms\n", tiempoPista);
	if (posicion.sector > cabezal.sector) {
		sectoresAtravezados = posicion.sector - cabezal.sector;
	} else {
		sectoresAtravezados = (CHS.sector) - (cabezal.sector)
				+ (posicion.sector) + 1;
	}
	tiempoSector = sectoresAtravezados * tiempoPorSector;
	printf("sectores recorridos: %d sectores \n", sectoresAtravezados);
	printf("tiempo Sector: %d ms\n", tiempoSector);
	uint16_t tiempoFinal = tiempoPista + tiempoSector;
	printf("el tiempo que tarda en alcanzar la posicion deseada es: %d ms\n",
			tiempoFinal);
	return tiempoFinal;
}

t_resAlgoritmo starvation(t_nodo **lista) {
	extern chs_t cabezal;
	t_resAlgoritmo p;
	t_nodo *aux;
	aux = *lista;
	uint16_t time;
	uint16_t menor = buscarTiempo(aux->infoNodo.pila->nro);
	p.nodoPila = aux->infoNodo.pila;
	p.nodoLista = aux;
	while (aux != NULL) {

		t_nroSector* auxPila = aux->infoNodo.pila;
		while (auxPila != NULL) {
			if ((time = buscarTiempo(auxPila->nro)) < menor
					&& auxPila->estado == 0) {

				p.nodoLista = aux;
				p.nodoPila = auxPila;
				menor = time;
			}
			auxPila = auxPila->sig;
		}

		aux = aux->sig;

	}

	return p;
}

void ordenarListaPedidos(t_nodo **lista) {
	t_nodo *aux = (t_nodo*) malloc(sizeof(t_nodo));
	aux = *lista;
	t_nodo *listaOrdenada;
	t_infoNodo info;
	listaOrdenada = NULL;
	while (aux != NULL) {
		info = aux->infoNodo;
		insertarEnLista(&listaOrdenada, info);
		aux = aux->sig;
	}
	*lista = listaOrdenada;
	free(listaOrdenada);
	return;
}

uint64_t calculaDif(chs_t CHS1, chs_t CHS2) {
	return abs(CHS1.pista - CHS2.pista);
}

t_resAlgoritmo noStarvation(t_nodo **lista) {
	/*extern chs_t cabezal;
	 ordenarListaPedidos(lista);
	 t_nodo *aux;
	 aux = *lista;
	 chs_t menor;
	 chs_t menor2;
	 pedido retorno;
	 t_nodo *p;
	 menor.pista = sizeof(uint16_t);
	 menor.sector = sizeof(uint16_t);
	 menor2.pista = sizeof(uint16_t);
	 menor2.sector = sizeof(uint16_t);

	 uint8_t encontrado = 0;
	 while ((aux != NULL) && (aux->infoNodo.dirFisica.pista < cabezal.pista)) {

	 aux = aux->sig;
	 }
	 if (aux == NULL) {
	 p = *lista;
	 *lista = (*lista)->sig;
	 retorno.dirFisica = p->infoNodo.dirFisica;
	 memcpy(retorno.info, p->infoNodo.info, 512);
	 retorno.tipo = p->infoNodo.tipo;

	 } else {
	 p = aux;
	 aux = aux->sig;
	 retorno.dirFisica = p->infoNodo.dirFisica;
	 memcpy(retorno.info, p->infoNodo.info, 512);
	 retorno.tipo = p->infoNodo.tipo;

	 }

	 return p->infoNodo;*/

	extern chs_t cabezal;

	uint64_t menor = calculaDif(cabezal, (*lista)->infoNodo.pila->nro);

	t_nodo* aux = *lista;

	t_resAlgoritmo p;
	p.nodoPila = (*lista)->infoNodo.pila;
	p.nodoLista = aux;

	while (aux != NULL) {
		t_nroSector* auxPila = aux->infoNodo.pila;
		while (auxPila != NULL) {
			uint64_t menorAux = calculaDif(cabezal, auxPila->nro);
			if (menorAux < menor && auxPila->estado == 0) {
				p.nodoLista = aux;
				p.nodoPila = auxPila;
				menor = menorAux;
			}
			auxPila = auxPila->sig;
		}
		aux = aux->sig;
	}

	return p;
}

void clean(uint16_t SI, uint16_t SF, uint32_t disco) {
	uint16_t i;
	char info[512];
	memset(info, '\0', 512);
	if (SI < SF) {
		for (i = SI; i <= SF; i++) {
			escribirSector(disco, i, info);
		}
	} else {
		printf("error: el sector final debe ser mayor que el sector inicial");
	}
}

chs_t aDireccionFisica(uint64_t direccionLogica) {
	extern chs_t CHS;
	chs_t devolver;
	devolver.cilindro = 1;
	devolver.pista = (direccionLogica % (CHS.pista * CHS.sector)) / CHS.sector;
	devolver.sector = (direccionLogica % (CHS.pista * CHS.sector)) % CHS.sector;
	return devolver;

}

void leerArchivoConfiguracion(char *path, char* modoInicio, char** IP,
		char** puerto, char** ID, uint8_t* algoritmo, char** pathConsola,
		uint16_t* flagDeLog, uint16_t* tiempoLectura, chs_t* CHS,
		uint16_t* tiempoEscritura, uint16_t* RPM, uint16_t* tiempoSaltoPistas) {
	uint16_t k, i = 0, parametro = 1;
	FILE *archivo = fopen(path, "r");
	char contenido[500];
	char c;
	char aux[20];
	while (!feof(archivo)) {
		fread(&c, 1, 1, archivo);
		if (c != ' ') {
			contenido[i] = c;
			i++;
		}
	}
	contenido[i] = '\0';
	i = 0;
	while (contenido[i] != '\0') {
		while (contenido[i] != ':') {
			i++;
		}
		i++;
		switch (parametro) {
		case 1:
			k = 0;

			while ((contenido[i] != ':') && (k < 8)) {

				modoInicio[k] = contenido[i];
				i++;
				k++;
			}

			modoInicio[k] = '\0';
			k = 0;
			i++;
			while (contenido[i] != ':') {
				i++;
				k++;
			}
			(*IP) = (char*) malloc(k);
			i -= k;
			k = 0;
			while (contenido[i] != ':') {
				(*IP)[k] = contenido[i];
				i++;
				k++;
			}
			(*IP)[k] = '\0';
			i++;
			k = 0;
			while (contenido[i] != '\n') {
				i++;
				k++;
			}
			(*puerto) = (char*) malloc(k);
			i -= k;
			k = 0;
			while (contenido[i] != '\n') {
				(*puerto)[k] = contenido[i];
				i++;
				k++;
			}
			(*puerto)[k] = '\0';
			break;
		case 2:
			aux[0] = contenido[i];
			aux[1] = '\0';
			*algoritmo = atoi(aux);
			break;

		case 3:
			k = 0;

			while (contenido[i] != '\n') {
				i++;
				k++;
			}
			*pathConsola = (char*) malloc((sizeof(char) * k));
			i -= k;
			k = 0;
			while (contenido[i] != '\n') {
				(*pathConsola)[k] = contenido[i];
				i++;
				k++;
			}
			(*pathConsola)[k] = '\0';
			break;
		case 4:
			k = 0;
			while (contenido[i] != '\n') {
				aux[k] = contenido[i];
				k++;
				i++;

			}

			aux[k] = '\0';
			*flagDeLog = atoi(aux);

			break;
		case 5:
			k = 0;
			while (contenido[i] != '\n') {
				i++;
				k++;
			}
			(*ID) = (char*) malloc(k);
			i -= k;
			k = 0;
			while (contenido[i] != '\n') {
				(*ID)[k] = contenido[i];
				i++;
				k++;
			}
			(*ID)[k] = '\0';
			break;
		case 6:
			k = 0;
			while (contenido[i] != ':') {
				aux[k] = contenido[i];
				k++;
				i++;
			}
			aux[k] = '\0';
			(CHS->cilindro) = atoi(aux);
			i++;
			k = 0;
			while (contenido[i] != ':') {
				aux[k] = contenido[i];
				k++;
				i++;
			}
			aux[k] = '\0';
			(CHS->pista) = atoi(aux);
			i++;
			k = 0;
			while (contenido[i] != '\n') {
				aux[k] = contenido[i];
				k++;
				i++;
			}
			aux[k] = '\0';
			(CHS->sector) = atoi(aux);

			break;
		case 7:
			k = 0;
			while (contenido[i] != '\n') {
				aux[k] = contenido[i];
				k++;
				i++;

			}
			aux[k] = '\0';
			*tiempoLectura = atoi(aux);

			break;
		case 8:
			k = 0;
			while (contenido[i] != '\n') {
				aux[k] = contenido[i];
				k++;
				i++;

			}
			aux[k] = '\0';
			*tiempoEscritura = atoi(aux);

			break;
		case 9:
			k = 0;
			while (contenido[i] != '\n') {
				aux[k] = contenido[i];
				k++;
				i++;

			}
			aux[k] = '\0';
			*RPM = atoi(aux);

			break;

		case 10:
			k = 0;
			while (contenido[i] != '\0') {
				aux[k] = contenido[i];
				k++;
				i++;

			}
			aux[k] = '\0';
			*tiempoSaltoPistas = atoi(aux);

			break;

		}
		parametro++;
	}
	fclose(archivo);

	return;
}

void llegarAPosicion(chs_t cabezal, chs_t pos, chs_t sig) {
	extern chs_t CHS;
	uint32_t tiempo;
	printf("posicion actual: %d:%d\n", cabezal.pista, cabezal.sector);
	printf("sector solicitado: %d:%d\n", pos.pista, pos.sector);

	if (((CHS.sector) < (pos.sector)) || ((CHS.sector) < (cabezal.sector))) {
		printf("error, muchos sectores ");
	} else if (((CHS.pista) < (pos.pista)) || ((CHS.pista) < (cabezal.pista))) {
		printf("error, hay menos pistas que la solicitada");
	} else {
		printf("sectores recorridos: ");
		while ((cabezal.pista) != (pos.pista)) {
			if ((cabezal.pista) > (pos.pista)) {
				cabezal.pista--;

			} else {
				cabezal.pista++;
			}
			printf("%d:%d, ", cabezal.pista, cabezal.sector);

		}
		while ((cabezal.sector) != (pos.sector)) {
			if ((cabezal.sector) == CHS.sector) {
				cabezal.sector = 0;
			} else {
				(cabezal.sector)++;
			}
			printf("%d:%d", cabezal.pista, cabezal.sector);

			if (abs(cabezal.sector - pos.sector) >= 1) {
				printf(", ");
			} else {
				printf(".\n");
			}
		}
	}
	tiempo = buscarTiempo(pos);
	printf("tiempo Consumido: %d ms\n", tiempo);
	printf("Proximo Sector: %d:%d:%d\n", sig.cilindro, sig.pista, sig.sector);
}

void eliminarPuntero(t_nodo **lista, t_infoNodo info) {
	t_nodo *aux;
	extern sem_t mutex;
	sem_wait(&mutex);
	aux = NULL;
	aux = *lista;
	t_nodo *ant;
	ant = NULL;
	while ((aux->sig != NULL)
			&& (memcmp(&aux->infoNodo, &info, sizeof(t_infoNodo)))) {
		ant = aux;
		aux = aux->sig;
	}
	if (memcmp(&aux->infoNodo, &info, sizeof(t_infoNodo))) {
		if (ant != NULL) {
			ant->sig = aux->sig;
		} else {
			*lista = aux->sig;
		}
	}

	free(aux);
	sem_post(&mutex);
	return;
}

void insertarEnLista(t_nodo **lista, t_infoNodo valor) {
	t_nodo *aux;
	t_nodo *ant;
	t_nodo *nuevo;
	extern sem_t mutex;
	extern sem_t sem_listaPedidos;
	extern uint64_t numeroPedidos;
	printf("bienvenido al insertar en lista\n");
	printf("mutex: %d\n", mutex);
	sem_wait(&mutex);
	nuevo = (t_nodo*) malloc(sizeof(t_nodo));
	nuevo->infoNodo = valor;
	nuevo->infoNodo.nroPedido = numeroPedidos;
	printf("llego hasta aca\n");
	if (*lista == NULL) {
		nuevo->sig = NULL;
		*lista = nuevo;
		printf("modo 1\n");
	} else if ((valor.nroPedido) < ((*lista)->infoNodo.nroPedido)) {
		printf("modo 2\n");
		nuevo->sig = *lista;
		*lista = nuevo;

	} else {

		printf("modo 3\n");

		aux = (*lista)->sig;
		ant = *lista;
		while ((aux != NULL) && (aux->infoNodo.nroPedido <= valor.nroPedido)) {
			ant = aux;
			aux = aux->sig;
		}
		if (aux == NULL) {
			ant->sig = nuevo;
			nuevo->sig = NULL;
		} else {
			ant->sig = nuevo;
			nuevo->sig = aux;
		}
	}
	sem_post(&sem_listaPedidos);
	sem_post(&mutex);
	printf("termine de ejecutar esta funcion\n");
	return;

}

t_paquete empaquetar(char* buf) {
	t_paquete nuevoPaquete; // Creo el nuevo paquete
	char* tresPrimeros = (char*) malloc(sizeof(char) * 3); // Reservo memoria para los primeros 3 bytes
	memcpy(tresPrimeros, buf, 3); // Guardo los 3 primeros bytes
	div_t d = div(atoi(tresPrimeros), 100); // Separo el primer byte
	nuevoPaquete.type = d.quot;
	nuevoPaquete.pLength = d.rem; // Separo el segundo y el tercer byte
	nuevoPaquete.payLoad = (char*) malloc(sizeof(char) * nuevoPaquete.pLength); // Reservo memoria para el Payload
	memcpy(nuevoPaquete.payLoad, buf + 3, nuevoPaquete.pLength); // Guardo el Payload
	free(tresPrimeros); // Libero memoria
	return nuevoPaquete; // Devuelvo el bufer empaquetado
}

uint16_t tiempoComprometidoDisco() {
	extern t_nodo* lista;
	extern chs_t cabezal;
	t_nodo *aux;
	aux = lista;
	uint16_t tiempo;
	t_nroSector* auxPila;
	while (aux != NULL) {
		auxPila = aux->infoNodo.pila;
		while (auxPila != NULL) {
			tiempo += buscarTiempo(auxPila->nro);
			auxPila = auxPila->sig;
		}
		aux = aux->sig;
	}
	return tiempo;
}

void apilar(t_nroSector **pila, char* info, chs_t nro) {
	t_nroSector *aux = (t_nroSector*) malloc(sizeof(t_nroSector));
	memcpy(aux->info, info, 512); //COMPROBAR SI ESTA BIEN
	aux->nro = nro;
	aux->sig = *pila;
	*pila = aux;
}

void trace(t_nodo **lista, t_dirLogica* listaSectores) {
	t_infoNodo aux;
	aux.origen = 0;
	aux.pila = NULL;
	char buffer[512];
	memset(buffer, '\0', 512);
	while (listaSectores != NULL) {
		chs_t CHS = aDireccionFisica(listaSectores->sector);
		apilar(&(aux.pila), buffer, CHS);
		listaSectores = listaSectores->sig;
	}
	insertarEnLista(lista, aux);
}

void desapilar(t_nroSector** pila, char* info, uint64_t *nro) {
	t_nroSector *aux;
	aux = *pila;
	*pila = (*pila)->sig;
	memcpy(info, aux->info, 512); //COMPROBAR SI ESTA BIEN
	*nro = aux->nro.cilindro * aux->nro.pista * aux->nro.sector;
	free(aux);
}

void parsearALaEscucha(int32_t descriptor, int64_t **cantPedidos) {
	extern t_nodo* lista;
	extern char *IP;
	extern char *puerto;
	extern chs_t CHS;
	ponermeALaEscucha(descriptor);
	aceptarConexion(descriptor, IP, puerto);
	char* respuesta = recibirPaquete(descriptor, 4163);
	uint8_t tipo = respuesta[0];

	uint16_t pLength = ((uint8_t) respuesta[1]) * 256
			+ ((uint8_t) respuesta[2]);

	uint32_t i;

	t_infoNodo nuevo;
	nuevo.tipo = tipo;
	nuevo.origen = 1;
	nuevo.pila = NULL;
	nuevo.descriptor = descriptor;
	printf("tipo: %d\n", tipo);
	char sector[512];
	switch (tipo) {
	case 1:
		memset(sector, '\0', 512);
		for (i = 3; i < pLength + 3;) {
			uint64_t dirLogica = ((uint8_t) respuesta[i]) * potencia(2, 56)
					+ ((uint8_t) respuesta[i + 1]) * potencia(2, 48)
					+ ((uint8_t) respuesta[i + 2]) * potencia(2, 40)
					+ ((uint8_t) respuesta[i + 3]) * potencia(2, 32)
					+ ((uint8_t) respuesta[i + 4]) * potencia(2, 24)
					+ ((uint8_t) respuesta[i + 5]) * potencia(2, 16)
					+ ((uint8_t) respuesta[i + 6]) * potencia(2, 8)
					+ ((uint8_t) respuesta[i + 7]) * potencia(2, 0);
			i += 8;

			printf("Nuevo sector a leer: %d.\n", dirLogica);

			chs_t chsAux = aDireccionFisica(dirLogica);

			printf("C: %d - H: %d - S: %d\n", chsAux.cilindro, chsAux.pista,
					chsAux.sector);

			apilar(&(nuevo.pila), sector, chsAux);

		}
		insertarEnLista(lista, nuevo);

		printf("Inserte en lista.\n");
		*cantPedidos += 1;
		break;
	case 2:
		for (i = 3; i < pLength + 3;) {
			uint64_t dirLogica = ((uint8_t) respuesta[i]) * potencia(2, 56)
					+ ((uint8_t) respuesta[i + 1]) * potencia(2, 48)
					+ ((uint8_t) respuesta[i + 2]) * potencia(2, 40)
					+ ((uint8_t) respuesta[i + 3]) * potencia(2, 32)
					+ ((uint8_t) respuesta[i + 4]) * potencia(2, 24)
					+ ((uint8_t) respuesta[i + 5]) * potencia(2, 16)
					+ ((uint8_t) respuesta[i + 6]) * potencia(2, 8)
					+ ((uint8_t) respuesta[i + 7]) * potencia(2, 0);
			i += 8;

			memset(sector, '\0', 512);

			memcpy(sector, respuesta + i, 512);

			printf("Nuevo sector a leer: %d.\n", dirLogica);

			chs_t chsAux = aDireccionFisica(dirLogica);

			printf("C: %d - H: %d - S: %d\n", chsAux.cilindro, chsAux.pista,
					chsAux.sector);

			apilar(&(nuevo.pila), sector, chsAux);
		}
		insertarEnLista(lista, nuevo);

		printf("Inserte en lista.\n");
		*cantPedidos += 1;
		break;
	case 4:
		send(descriptor, "si", 2, 0);
		break;
	}
}

void correrAtencionDePedidos(t_correrPedido *param) {
	int32_t descriptor;
	uint8_t i;
	uint64_t tiempo;
	extern char modoInicio[8];
	descriptor = param->descriptor;
	printf("entro en el thread de sockets; descriptor: %d.\n", descriptor);
	uint8_t faltaHS = 1;
	extern char* puerto;
	extern char* IP;
	int64_t **cantPedidos = 0;
	uint64_t cantSectores;
	extern char* ID;
	char* respuesta;

	while (1) {
		printf("probando hilo correrAtencionPedidos\n");
		if (faltaHS) {
			if (strcmp(modoInicio, "CONNECT") == 0) {

				char* HS;
				HS = cargarPaqueteRaid(ID, cantSectores, IP, puerto);
				descriptor = crearCliente(IP, puerto);
				enviarPaquete(descriptor, HS);
				respuesta = recibirPaquete(descriptor, 3);
				faltaHS = controlarHandShake(respuesta);
				convertirAServidor(&descriptor, IP, puerto);

			} else if (strcmp(modoInicio, "LISTEN") == 0) {

				descriptor = crearServidor(IP, puerto);
				ponermeALaEscucha(descriptor);
				int32_t cliente = aceptarConexion(descriptor, IP, puerto);
				respuesta = recibirPaquete(cliente, 3);
				faltaHS = controlarHandShake(respuesta);
				char aEnviar[3];
				strcpy(aEnviar, "\0\0\0");
				enviarPaquete(cliente, aEnviar);
			}
		}
		parsearALaEscucha(descriptor, &cantPedidos);
		printf("probando hilo correrAtencionPedidos2\n");
		tiempo = tiempoComprometidoDisco();
		char *respuesta;
		crearPaqueteTiempo(tiempo, &respuesta);
		enviarPaquete(descriptor, respuesta);
	}
	return;

}

char* cargarEstructura(t_infoNodo cafecito) {
	char* rta;
	uint8_t i;
	t_nroSector *aux = cafecito.pila;
	for (i = 0; aux != NULL; i++) {
		aux = aux->sig;
	}
	rta = (char*) malloc((i * 520) + 3);
	rta[0] = 1;
	rta[1] = div(i * 520, 256).quot;
	rta[2] = div(i * 520, 256).rem;
	for (i = 3; cafecito.pila != NULL; i += 520) {
		char info[512];
		uint64_t nroSector;
		desapilar(&(cafecito.pila), info, &nroSector);

		rta[i] = nroSector / potencia(2, 56);
		rta[i + 1] = (nroSector / potencia(2, 48))
				- (((uint8_t) rta[i]) * potencia(2, 8));
		rta[i + 2] = (nroSector / potencia(2, 40))
				- ((((uint8_t) rta[i]) * potencia(2, 16))
						+ (((uint8_t) rta[i + 1]) * potencia(2, 8)));
		rta[i + 3] = (nroSector / potencia(2, 32))
				- ((((uint8_t) rta[i]) * potencia(2, 24))
						+ (((uint8_t) rta[i + 1]) * potencia(2, 16))
						+ (((uint8_t) rta[i + 2]) * potencia(2, 8)));
		rta[i + 4] = (nroSector / potencia(2, 24))
				- ((((uint8_t) rta[i]) * potencia(2, 32))
						+ (((uint8_t) rta[i + 1]) * potencia(2, 24))
						+ (((uint8_t) rta[i + 2]) * potencia(2, 16))
						+ (((uint8_t) rta[i + 3]) * potencia(2, 8)));
		rta[i + 5] = (nroSector / potencia(2, 16))
				- ((((uint8_t) rta[i]) * potencia(2, 40))
						+ (((uint8_t) rta[i + 1]) * potencia(2, 32))
						+ (((uint8_t) rta[i + 2]) * potencia(2, 24))
						+ (((uint8_t) rta[i + 3]) * potencia(2, 16))
						+ (((uint8_t) rta[i + 4]) * potencia(2, 8)));
		rta[i + 6] = (nroSector / potencia(2, 8))
				- ((((uint8_t) rta[i]) * potencia(2, 48))
						+ (((uint8_t) rta[i + 1]) * potencia(2, 40))
						+ (((uint8_t) rta[i + 2]) * potencia(2, 32))
						+ (((uint8_t) rta[i + 3]) * potencia(2, 24))
						+ (((uint8_t) rta[i + 4]) * potencia(2, 16))
						+ (((uint8_t) rta[i + 5]) * potencia(2, 8)));
		rta[i + 7] = nroSector
				- ((((uint8_t) rta[i]) * potencia(2, 56))
						+ (((uint8_t) rta[i + 1]) * potencia(2, 48))
						+ (((uint8_t) rta[i + 2]) * potencia(2, 40))
						+ (((uint8_t) rta[i + 3]) * potencia(2, 32))
						+ (((uint8_t) rta[i + 4]) * potencia(2, 24))
						+ (((uint8_t) rta[i + 5]) * potencia(2, 16))
						+ (((uint8_t) rta[i + 6]) * potencia(2, 8)));

		memcpy(rta + i + 8, info, 512);
	}
	return rta;
}

void buscaYElimina(uint64_t nroPedido) {
	extern t_respuesta* respuesta;
	t_respuesta* aux = respuesta;
	if (aux != NULL) {
		if (aux->nroPedido == nroPedido) {
			respuesta = NULL;
			free(aux);
		} else {
			t_respuesta* auxSig = aux->sig;
			while (auxSig != NULL && auxSig->nroPedido != nroPedido) {
				aux = auxSig;
				auxSig = auxSig->sig;
			}
			if (auxSig != NULL) {
				aux->sig = auxSig->sig;
				free(auxSig);
			}
		}
	}
}

int8_t verificarPila(t_nroSector* pilaFte) {
	int8_t listo = 1;
	t_nroSector* aux = pilaFte;
	while (aux != NULL && listo) {
		if (aux->estado == 0) {
			listo = 0;
		}
		aux = aux->sig;
	}
	return listo;
}

void planificar(t_nodo **lista) {
	extern t_respuesta *respuesta;
	char mensajeTrace[18];
	char* envio;
	extern int32_t consola;
	extern uint32_t disco;
	extern chs_t cabezal;
	extern uint8_t algoritmo;
	extern sem_t sem_listaPedidos;
	t_resAlgoritmo info, infoSiguiente;
	printf("entre en el thread de planificacion\n");
	while (1) {
		sem_wait(&sem_listaPedidos);
		if (algoritmo == 0) {
			info = noStarvation(lista);
		} else if (algoritmo == 1) {
			info = starvation(lista);
		} else {
			perror("algoritmo seleccionado invalido");
			return;
		}

		info.nodoPila->estado = 1;

		if (info.nodoLista->infoNodo.origen == 0) {
			if (algoritmo == 0) {
				infoSiguiente = noStarvation(lista);
			} else if (algoritmo == 1) {
				infoSiguiente = starvation(lista);
			} else {
				perror("algoritmo seleccionado invalido");
				return;
			}
			mensajeTrace[0] = div(cabezal.cilindro, 256).quot;
			mensajeTrace[1] = div(cabezal.cilindro, 256).rem;
			mensajeTrace[2] = div(cabezal.pista, 256).quot;
			mensajeTrace[3] = div(cabezal.pista, 256).rem;
			mensajeTrace[4] = div(cabezal.sector, 256).quot;
			mensajeTrace[5] = div(cabezal.sector, 256).rem;
			mensajeTrace[6] = div(info.nodoPila->nro.cilindro, 256).quot;
			mensajeTrace[7] = div(info.nodoPila->nro.cilindro, 256).rem;
			mensajeTrace[8] = div(info.nodoPila->nro.pista, 256).quot;
			mensajeTrace[9] = div(info.nodoPila->nro.pista, 256).rem;
			mensajeTrace[10] = div(info.nodoPila->nro.sector, 256).quot;
			mensajeTrace[11] = div(info.nodoPila->nro.sector, 256).rem;
			mensajeTrace[12] =
					div(infoSiguiente.nodoPila->nro.cilindro, 256).quot;
			mensajeTrace[13] =
					div(infoSiguiente.nodoPila->nro.cilindro, 256).rem;
			mensajeTrace[14] = div(infoSiguiente.nodoPila->nro.pista, 256).quot;
			mensajeTrace[15] = div(infoSiguiente.nodoPila->nro.pista, 256).rem;
			mensajeTrace[16] =
					div(infoSiguiente.nodoPila->nro.sector, 256).quot;
			mensajeTrace[17] = div(infoSiguiente.nodoPila->nro.sector, 256).rem;
			send(consola, mensajeTrace, 18, 0);

		} else if (info.nodoLista->infoNodo.origen == 1) {
			if (info.nodoLista->infoNodo.tipo == 1) {
				printf("escribo en disco, en el sector: %d:%d\n",
						info.nodoPila->nro.pista, info.nodoPila->nro.sector);
				escribirSector(
						disco,
						(info.nodoPila->nro.cilindro * info.nodoPila->nro.pista
								- info.nodoPila->nro.sector), info.nodoPila->info);
					} else if(info.nodoLista->infoNodo.tipo == 2) {
						printf("leo en disco, en el sector: %d:%d\n", info.nodoPila->nro.pista, info.nodoPila->nro.sector );
				leerSector(disco, (info.nodoPila->nro.cilindro*info.nodoPila->nro.pista-info.nodoPila->nro.sector), info.nodoPila->info);
				int8_t listo = verificarPila(info.nodoLista->infoNodo.pila);
				if(listo) {
					envio = cargarEstructura(info.nodoLista->infoNodo);
					send(info.nodoLista->infoNodo.descriptor,envio,sizeof(envio),0);
					/*MODIFICAR*/buscaYElimina(info.nodoLista->infoNodo.nroPedido);
				}
			} else {
				perror("tipo de peticion desconocido");
			}
			} else {
				perror("origen de pedido desconocido");
				return;
			}
		cabezal = info.nodoPila->nro;
	}

}

uint64_t potencia(uint16_t base, uint16_t exponente) {
	uint64_t res;
	uint16_t i;
	for (res = i = 1; i <= exponente; i++) {
		res = res * base;
	}
	return res;
}

uint64_t charAInt(char* cadena) {
	uint16_t i, k;
	uint64_t num;
	for (k = 0; cadena[k] != '\0'; k++) {
	}
	for (i = 0; cadena[i] != '\0'; i++) {
		num += potencia(cadena[i], (k - i + 1));
	}
	return num;

}

void insertaEnListaDir(t_dirLogica** fte, uint64_t nroSector) {
	t_dirLogica* nuevo = (t_dirLogica*) malloc(sizeof(t_dirLogica));
	nuevo->sig = *fte;
	nuevo->sector = nroSector;
	*fte = nuevo;
}

char* comprenderConsola(char* mensaje, int32_t consola) {
	extern chs_t cabezal;
	char aux[8];
	char* respuesta;
	extern t_nodo *lista;
	uint8_t cant, j;
	extern uint32_t disco;
	uint64_t SI, SF;
	uint16_t i;
	t_infoNodo inserta;
	t_dirLogica* inserta2;
	if (strcmp(mensaje, "info:") == 0) {
		printf("Inicia procesamiento de info\n");
		respuesta = (char*) malloc(7);
		respuesta[0] = 0;
		respuesta[1] = div(cabezal.cilindro, 256).quot;
		respuesta[2] = div(cabezal.cilindro, 256).rem;
		respuesta[3] = div(cabezal.pista, 256).quot;
		respuesta[4] = div(cabezal.pista, 256).rem;
		respuesta[5] = div(cabezal.sector, 256).quot;
		respuesta[6] = div(cabezal.sector, 256).rem;
		send(consola, respuesta, sizeof(respuesta), 0);

	} else {
		memcpy(aux, mensaje, 5);
		if (strcmp(aux, "clean") == 0) {
			printf("Inicia procesamiento de Clean\n");
			SI = (mensaje[5] * potencia(2, 56)) + (mensaje[6] * potencia(2, 48))
					+ (mensaje[7] * potencia(2, 40))
					+ (mensaje[8] * potencia(2, 32))
					+ (mensaje[9] * potencia(2, 24))
					+ (mensaje[10] * potencia(2, 16))
					+ (mensaje[11] * potencia(2, 8)) + mensaje[12];
			SF = (mensaje[13] * potencia(2, 56))
					+ (mensaje[14] * potencia(2, 48))
					+ (mensaje[15] * potencia(2, 40))
					+ (mensaje[16] * potencia(2, 32))
					+ (mensaje[17] * potencia(2, 24))
					+ (mensaje[18] * potencia(2, 16))
					+ (mensaje[19] * potencia(2, 8)) + mensaje[20];
			clean(SI, SF, disco);
			respuesta = (char*) malloc(1);
			respuesta[0] = 1;
			send(consola, respuesta, sizeof(respuesta), 0);
		} else if (strcmp(aux, "trace") == 0) {
			printf("Inicio procesamiento de Trace\n");
			for (i = 0; mensaje[i] != '\0'; i++)
				;
			respuesta = (char*) malloc(i + 1);
			memset(respuesta, '\0', i + 1);
			respuesta[0] = 2;
			inserta.origen = 0;
			for (i = 6; mensaje[i] != '\0' && cant < 5; i++, cant++) {
				j = 0;
				memset(aux, 0, sizeof(aux));
				while (mensaje[i] != ' ' && mensaje[i] != '\0') {
					aux[j] = mensaje[i];
					j++;
					i++;
				}
				insertaEnListaDir(&inserta2, atoi(aux));
			}
			trace(&lista, inserta2);

		}
	}
	return respuesta;
}

void consolar() {
	extern chs_t CHS;
	extern char* path;
	char* mensaje = NULL;
	char chsmsg[6];
	int32_t descriptor;
	extern int32_t consola;
	char* respuesta = NULL;
	printf("entro en el thread de consola\n");
	descriptor = crearServerUnix(path);
	uint32_t queEscucho = meQuedoEscuchando(descriptor, sizeof(uint64_t));
	consola = aceptarConexionEnUnix(descriptor, path);
	while (1) {
		printf("recibo de la consola\n");
		recv(consola, mensaje, 25, 0);
		respuesta = comprenderConsola(mensaje, consola);
	}
}

void senalFin() {

	extern uint32_t disco;
	extern int32_t descriptor;
	extern int32_t remote_client;
	extern pthread_t tidPedido;
	extern uint64_t lenDisco;
	extern pthread_t tidPlanificar;
	extern char* ptrDisco;
	extern char* sectorOcupado;
	extern uint64_t lenDisco;
	uint64_t i;

	if (descriptor != 0)
		close(descriptor);
	if (remote_client != 0)
		close(remote_client);
	close(disco);
	if (ptrDisco != NULL
	)
		munmap(ptrDisco, lenDisco);
	if (tidPedido != 0)
		pthread_kill(tidPedido, 0);
	if (tidPlanificar != 0)
		pthread_kill(tidPlanificar, 0);
	for (i = 0; i < lenDisco; i++) {
		if (sectorOcupado[i] == 1) {
			if (msync(ptrDisco + i * 512, 512, MS_SYNC) == -1) {
				printf("error en el msync()\n");
				signal(SIGUSR1, senalFin);
				return;
			};
		}
	}
	printf("el proceso se finalizo debido a una seÃ±al\n");
}

char* cargarPaqueteRaid(char* ID, uint64_t sectores, char* IP, char* puerto) {
	uint16_t tamano = strlen(ID) + (sizeof(sectores)) + strlen(IP)
			+ strlen(puerto) + 3;
	char* paquete = (char*) malloc(tamano);
	tamano -= 3;
	uint64_t i = 3;
	uint64_t k = 0;
	paquete[0] = 0;
	paquete[1] = tamano / 256;
	paquete[2] = tamano % 256;
	for (k = 0; ID[k] != '\0'; k++, i++) {
		paquete[i] = ID[k];
	}
	paquete[i] = '@';
	i++;
	for (k = 0; k < 8; k++, i++) {
		paquete[i] = sectores / potencia(2, (56 - 8 * k));
		sectores -= sectores / (potencia(2, 56)) * potencia(2, 56);
	}
	for (k = 0; IP[k] != '\0'; k++, i++) {
		paquete[i] = IP[k];
	}
	paquete[i] = '@';
	i++;
	for (k = 0; puerto[k] != '\0'; i++, k++) {
		paquete[i] = ID[k];
	}
	return paquete;
}

